package org.mx.service.server.config;

import org.mx.service.rest.cors.CorsConfigBean;
import org.mx.service.rest.graphql.GraphQLConfigBean;
import org.mx.service.rest.graphql.GraphQLFactory;
import org.mx.service.server.CommServerConfigBean;
import org.mx.service.server.CommServerFactory;
import org.mx.service.server.RestfulServerConfigBean;
import org.mx.service.server.RestfulServerFactory;
import org.mx.service.server.ServletServerConfigBean;
import org.mx.service.server.ServletServerFactory;
import org.mx.service.server.WebServerConfigBean;
import org.mx.service.server.WebServerFactory;
import org.mx.service.server.WebsocketServerConfigBean;
import org.mx.service.server.WebsocketServerFactory;
import org.mx.service.server.jmx.CommServer;
import org.mx.service.server.jmx.RestfulServer;
import org.mx.service.server.jmx.ServiceMXBeanLoader;
import org.mx.service.server.jmx.ServletServer;
import org.mx.service.server.jmx.WebServer;
import org.mx.service.server.jmx.WebsocketServer;
import org.mx.service.server.websocket.WsSessionManager;
import org.mx.service.server.websocket.rule.DdosFilterRule;
import org.mx.service.server.websocket.rule.ListFilterRule;
import org.mx.spring.config.SpringConfig;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;

/**
 * REST服务器的Java Configure定义
 * 加载配置： classpath:server.properties
 *
 * @author : john.peng date : 2017/10/6
 */
@Import({ SpringConfig.class })
public class ServerConfig {
	/**
	 * 创建Web服务配置对象
	 * @return Web服务配置对象
	 */
	@ConditionalOnProperty(prefix = "web", name = "enabled", havingValue = "true")
	@Bean
	public WebServerConfigBean webServerConfigBean() {
		return new WebServerConfigBean();
	}

	/**
	 * 创建RESTful服务配置对象
	 *
	 * @return RESTful服务配置对象
	 */
	@ConditionalOnProperty(prefix = "restful", name = "enabled", havingValue = "true")
	@Bean
	public RestfulServerConfigBean restfulServerConfigBean() {
		return new RestfulServerConfigBean();
	}

	/**
	 * 创建Servlet服务配置对象
	 *
	 * @return Servlet服务配置对象
	 */
	@ConditionalOnProperty(prefix = "servlet", name = "enabled", havingValue = "true")
	@Bean
	public ServletServerConfigBean servletServerConfigBean() {
		return new ServletServerConfigBean();
	}

	/**
	 * 创建WebSocket配置对象
	 *
	 * @return WebSocket配置对象
	 */
	@ConditionalOnProperty(prefix = "websocket", name = "enabled", havingValue = "true")
	@Bean
	public WebsocketServerConfigBean websocketServerConfigBean() {
		return new WebsocketServerConfigBean();
	}

	/**
	 * 创建COMM配置对象
	 *
	 * @param env Spring IoC上下文环境
	 * @return COMM配置对象
	 */
	@ConditionalOnExpression("${tcp.enabled:true}||${udp.enabled:true}")
	@Bean
	public CommServerConfigBean commServerConfigBean(Environment env) {
		return new CommServerConfigBean(env);
	}

	/**
	 * 创建跨域配置对象
	 *
	 * @return 跨域配置对象
	 */
	@ConditionalOnProperty(prefix = "cors", name = "enabled", havingValue = "true")
	@Bean
	public CorsConfigBean corsConfigBean() {
		return new CorsConfigBean();
	}

	/**
	 * 根据配置文件创建GraphQL配置信息对象
	 *
	 * @return GraphQL配置信息对象
	 */
	@ConditionalOnExpression("'${graphql.schema}'.length() > 0")
	@Bean
	public GraphQLConfigBean graphQLConfigBean() {
		return new GraphQLConfigBean();
	}

	/**
	 * 根据配置创建GraphQL工厂
	 *
	 * @param context Spring IoC上下文
	 * @return GraphQL工厂
	 */
	@ConditionalOnBean(GraphQLConfigBean.class)
	@Bean(name = "graphQLFactory", initMethod = "init", destroyMethod = "destroy")
	public GraphQLFactory graphQLFactory(ApplicationContext context) {
		return new GraphQLFactory(context);
	}

	/**
	 * 根据配置创建WebSocket会话管理器
	 *
	 * @param context    Spring IoC上下文
	 * @param configBean WebSocket服务器配置信息对象
	 * @return WebSocket会话管理器
	 */
	@ConditionalOnBean(WebsocketServerConfigBean.class)
	@Bean(name = "wsSessionManager", initMethod = "init", destroyMethod = "destroy")
	public WsSessionManager wsSessionManager(ApplicationContext context, WebsocketServerConfigBean configBean) {
		return new WsSessionManager(context, configBean);
	}

	/**
	 * 创建黑白名单过滤器规则
	 *
	 * @param websocketServerConfigBean WebSocket配置对象
	 * @return 规则
	 */
	@ConditionalOnBean(WebsocketServerConfigBean.class)
	@Bean(name = "listFilterRule")
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	public ListFilterRule listFilterRule(WebsocketServerConfigBean websocketServerConfigBean) {
		return new ListFilterRule(websocketServerConfigBean.getWebSocketFilter());
	}

	/**
	 * 创建DDOS过滤器规则
	 *
	 * @param websocketServerConfigBean WebSocket配置对象
	 * @return 规则
	 */
	@ConditionalOnBean(WebsocketServerConfigBean.class)
	@Bean(name = "ddosFilterRule")
	@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	public DdosFilterRule ddosFilterRule(WebsocketServerConfigBean websocketServerConfigBean) {
		return new DdosFilterRule(websocketServerConfigBean.getWebSocketFilter());
	}

	/**
	 * 创建基于Jetty的Web服务器工厂
	 * @param context Spring IoC上下文
	 * @param webServerConfigBean Web服务配置对象
	 * @param webServerMXBean	Web服务器MXBean对象
	 * @return Web服务器工厂
	 */
	@ConditionalOnBean(WebServerConfigBean.class)
	@Bean(name = "webServerFactory", initMethod = "init", destroyMethod = "destroy")
	public WebServerFactory webServerFactory(ApplicationContext context, WebServerConfigBean webServerConfigBean,
			WebServer webServerMXBean) {
		WebServerFactory factory = new WebServerFactory(context, webServerConfigBean, webServerMXBean);
		webServerMXBean.setHttpServerFactory(factory);
		return factory;
	}

	/**
	 * 创建基于TCP/IP通信的服务器工厂
	 *
	 * @param context              Spring IoC上下文
	 * @param commServerConfigBean COMM通信配置对象
	 * @param commServerMXBean	   Comm MXBean对象
	 * @return 通信服务器工厂
	 */
	@ConditionalOnBean(CommServerConfigBean.class)
	@Bean(name = "commServerFactory", initMethod = "init", destroyMethod = "destroy")
	public CommServerFactory commServerFactory(ApplicationContext context, CommServerConfigBean commServerConfigBean,
			CommServer commServerMXBean) {
		CommServerFactory factory = new CommServerFactory(context, commServerConfigBean);
		commServerMXBean.setCommServerFactory(factory);
		return factory;
	}

	/**
	 * 创建RESTful服务器工厂
	 *
	 * @param context                 Spring IoC上下文
	 * @param restfulServerConfigBean RESTful配置对象
	 * @param restfulServerMXBean	  Restful MXBean对象
	 * @return RESTful服务器工厂
	 */
	@ConditionalOnBean(RestfulServerConfigBean.class)
	@Bean(name = "restfulServerFactory", initMethod = "init", destroyMethod = "destroy")
	public RestfulServerFactory restfulServerFactory(ApplicationContext context,
			RestfulServerConfigBean restfulServerConfigBean, RestfulServer restfulServerMXBean) {
		RestfulServerFactory factory = new RestfulServerFactory(context, restfulServerConfigBean, restfulServerMXBean);
		restfulServerMXBean.setHttpServerFactory(factory);
		return factory;
	}

	/**
	 * 创建Servlet服务器工厂
	 *
	 * @param context                 Spring IoC上下文
	 * @param servletServerConfigBean Servlet服务配置对象
	 * @param servletServerMXBean	  Servlet MXBean对象
	 * @return Servlet服务器工厂
	 */
	@ConditionalOnBean(ServletServerConfigBean.class)
	@Bean(name = "servletServerFactory", initMethod = "init", destroyMethod = "destroy")
	public ServletServerFactory servletServerFactory(ApplicationContext context,
			ServletServerConfigBean servletServerConfigBean, ServletServer servletServerMXBean) {
		ServletServerFactory factory = new ServletServerFactory(context, servletServerConfigBean, servletServerMXBean);
		servletServerMXBean.setHttpServerFactory(factory);
		return factory;
	}

	/**
	 * 创建Websocket服务器工厂
	 *
	 * @param context                   Spring IoC上下文
	 * @param websocketServerConfigBean WebSocket配置对象
	 * @param websocketServerMXBean     Websocket服务器JMX MXBean对象
	 * @return Websocket服务器工厂
	 */
	@ConditionalOnBean(WebsocketServerConfigBean.class)
	@Bean(name = "websocketServerFactory", initMethod = "init", destroyMethod = "destroy")
	public WebsocketServerFactory websocketServerFactory(ApplicationContext context,
			WebsocketServerConfigBean websocketServerConfigBean, WebsocketServer websocketServerMXBean) {
		WebsocketServerFactory factory = new WebsocketServerFactory(context, websocketServerConfigBean,
				websocketServerMXBean);
		websocketServerMXBean.setHttpServerFactory(factory);
		return factory;
	}
	
	/**
	 * 创建Comm服务器 MXBean
	 * @param configBean Comm服务器配置信息对象
	 * @return Comm服务器MXBean对象
	 */
	@ConditionalOnBean(CommServerConfigBean.class)
	@Bean("commServerMXBean")
	public CommServer createCommServerMXBean(CommServerConfigBean configBean) {
		return new CommServer(configBean);
	}

	/**
	 * 创建Web服务器 MXBean
	 * @param configBean Web服务器配置信息对象
	 * @return Web服务器MXBean对象
	 */
	@ConditionalOnBean(WebServerConfigBean.class)
	@Bean("webServerMXBean")
	public WebServer createWebServerMXBean(WebServerConfigBean configBean) {
		return new WebServer(configBean);
	}

	/**
	 * 创建Websocket服务器 MXBean
	 * @param configBean Websocket服务器配置信息对象
	 * @return Websocket服务器MXBean对象
	 */
	@ConditionalOnBean(WebsocketServerConfigBean.class)
	@Bean("websocketServerMXBean")
	public WebsocketServer createWebsocketServerMXBean(WebsocketServerConfigBean configBean) {
		return new WebsocketServer(configBean);
	}

	/**
	 * 创建Servlet服务器 MXBean
	 * @param configBean Servlet服务器配置信息对象
	 * @return Servlet服务器MXBean对象
	 */
	@ConditionalOnBean(ServletServerConfigBean.class)
	@Bean("servletServerMXBean")
	public ServletServer createServletServerMXBean(ServletServerConfigBean configBean) {
		return new ServletServer(configBean);
	}

	/**
	 * 创建Restful服务器 MXBean
	 * @param configBean Restful服务器配置信息对象
	 * @return restful服务器MXBean对象
	 */
	@ConditionalOnBean(RestfulServerConfigBean.class)
	@Bean("restfulServerMXBean")
	public RestfulServer createRestfulServerMXBean(RestfulServerConfigBean configBean) {
		return new RestfulServer(configBean);
	}

	/**
	 * 加载注册相关的JMX MXBean
	 * @param context Spring IoC容器上下文
	 * @return JMX MXBean加载器
	 */
	@Bean
	public ServiceMXBeanLoader loadMXBean(ApplicationContext context) {
		return new ServiceMXBeanLoader(context);
	}
}